package com.avyss.flyingpoints;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;

import com.avyss.flyingpoints.scene.Scene;

public class CustomSurfaceView extends SurfaceView 
	implements SurfaceHolder.Callback, OnTouchListener {

	private final SurfaceHolder surfaceHolder;
	
	private final Thread drawingThread;
	
	private Scene scene;
	private Object sceneSyncObject  = new String("scene access synchronization object");
	
	private volatile int sleepTime;
	private Object sleepSyncObject = new String("sleep synchronization object");
	
	private static final int SLEEP_RUNNING_MS = 10;
	private static final int SLEEP_STOPPED_MS = Integer.MAX_VALUE;
	
	public CustomSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);

        setOnTouchListener(this);
        
		surfaceHolder = getHolder();
		surfaceHolder.addCallback(this);
		
		sleepTime = SLEEP_RUNNING_MS;
		drawingThread = new Thread(new DrawingThread());
		drawingThread.start();
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Log.d(this.getClass().getName(), "surface created");
		
		synchronized (sceneSyncObject) {
			//nothing to do here before the surface dimensions are known
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		Log.d(this.getClass().getName(), "sufrace changed");
		
		synchronized (sceneSyncObject) {
			scene = new Scene(width, height);
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.d(this.getClass().getName(), "surface is destroyed");
		
		synchronized (sceneSyncObject) {
			scene = null;
		}		
	}

	@Override
	public boolean onTouch(View view, MotionEvent ev) {
		Log.d(this.getClass().getName(), "sufrace clicked - create new scene");
		
		synchronized (sceneSyncObject) {
			if (scene != null) {
				scene.placeLeader(ev.getX(), ev.getY());
			}
		}
		
		return true;
	}

	public void pauseMovements() {
		Log.d(this.getClass().getName(), "pausing the movements");
		
		synchronized (sceneSyncObject) {
			sleepTime = SLEEP_STOPPED_MS;
		}
	}

	public void resumeMovements() {
		Log.d(this.getClass().getName(), "resuming movements");

		// don't interrupt the drawing thread during the scene access
		synchronized (sceneSyncObject) {
			sleepTime = SLEEP_RUNNING_MS;
			drawingThread.interrupt();
		}
	}

	class DrawingThread implements Runnable {
		
		@Override
		public void run() {
			
			long lastUpdateTime = System.currentTimeMillis();
			
			while(true) {
				try {
					synchronized (sleepSyncObject) {
						sleepSyncObject.wait(sleepTime);
					};
				} catch (InterruptedException e) {
					Log.d(this.getClass().getName(), "thread returned to running");
					continue;
				}
				
				synchronized (sceneSyncObject) {
					if (scene == null) {
						continue;
					}
					
					// check how much time passed since last scene state update 
					long currSystemTime = System.currentTimeMillis();
					long timeStepMs = currSystemTime - lastUpdateTime;
					lastUpdateTime = currSystemTime;
					
					// If too much time had passed - ignore the actual time
					// and use standard time step
					if (timeStepMs > 100 * SLEEP_RUNNING_MS) {
						timeStepMs = SLEEP_RUNNING_MS;
					}
					
					scene.calcNextState(timeStepMs);
						
					Canvas canvas = surfaceHolder.lockCanvas();
					if (canvas == null) {
						continue;
					}
					
					try {
						scene.drawCurrentState(canvas);
					} finally {
						surfaceHolder.unlockCanvasAndPost(canvas);
					}
					
				}
			}
		}
		
	}

}
